Update shape handling
authorAlexander Larsson <alexl@redhat.com>
Thu, 27 Aug 2009 16:04:07 +0000 (18:04 +0200)
committerAlexander Larsson <alexl@redhat.com>
Mon, 31 Aug 2009 13:06:01 +0000 (15:06 +0200)
For toplevels, never apply clip as shape, instead apply shape.
This way we don't have to re-set it all the time as the window size
changes. Furthermore, this change fixes unsetting a shape on a
toplevel window which didn't actually unset the shape before.

Additionally we never apply clips as shape if the shape would just
be the same as the regular window size. This means we won't unnecessarily
add a useless shape to most native child windows (and additionally this
helps apps that do weird X stuff that don't expect these shaped windows).

gdk/gdkinternals.h
gdk/gdkwindow.c

index 4cc45f912c0f125cd16be9b7bbd17dc18f841e23..e35d9392db7f2fee9683fcbe13a8707416daca67 100644 (file)
@@ -262,6 +262,7 @@ struct _GdkWindowObject
   guint visibility : 2; /* The visibility wrt the toplevel (i.e. based on clip_region) */
   guint native_visibility : 2; /* the native visibility of a impl windows */
   guint viewable : 1; /* mapped and all parents mapped */
+  guint applied_shape : 1;
 
   guint num_offscreen_children;
   GdkWindowPaint *implicit_paint;
index dfacc15a2067e875e88d263a55dea0a9b7921e6e..2785702fe7f1d82f0cc0054ecde0061c45527dff 100644 (file)
@@ -822,6 +822,61 @@ gdk_window_update_visibility_recursively (GdkWindowObject *private,
     }
 }
 
+static gboolean
+should_apply_clip_as_shape (GdkWindowObject *private)
+{
+  return
+    gdk_window_has_impl (private) &&
+    /* Not for offscreens */
+    private->window_type != GDK_WINDOW_OFFSCREEN &&
+    /* or for toplevels */
+    !gdk_window_is_toplevel (private) &&
+    /* or for foreign windows */
+    private->window_type != GDK_WINDOW_FOREIGN &&
+    /* or for the root window */
+    private->window_type != GDK_WINDOW_ROOT;
+}
+
+static void
+apply_shape (GdkWindowObject *private,
+            GdkRegion *region)
+{
+  GdkWindowImplIface *impl_iface;
+
+  /* We trash whether we applied a shape so that
+     we can avoid unsetting it many times, which
+     could happen in e.g. apply_clip_as_shape as
+     windows get resized */
+  impl_iface = GDK_WINDOW_IMPL_GET_IFACE (private->impl);
+  if (region)
+    impl_iface->shape_combine_region ((GdkWindow *)private,
+                                     region, 0, 0);
+  else if (private->applied_shape)
+    impl_iface->shape_combine_region ((GdkWindow *)private,
+                                     NULL, 0, 0);
+
+  private->applied_shape = region != NULL;
+}
+
+static void
+apply_clip_as_shape (GdkWindowObject *private)
+{
+  GdkRectangle r;
+
+  r.x = r.y = 0;
+  r.width = private->width;
+  r.height = private->height;
+
+  /* We only apply the clip region if would differ
+     from the actual clip region implied by the size
+     of the window. This is to avoid unneccessarily
+     adding meaningless shapes to all native subwindows */
+  if (!gdk_region_rect_equal (private->clip_region, &r))
+    apply_shape (private, private->clip_region);
+  else
+    apply_shape (private, NULL);
+}
+
 static void
 recompute_visible_regions_internal (GdkWindowObject *private,
                                    gboolean recalculate_clip,
@@ -971,21 +1026,8 @@ recompute_visible_regions_internal (GdkWindowObject *private,
     }
 
   if (clip_region_changed &&
-      gdk_window_has_impl (private) &&
-      /* Not for offscreens */
-      private->window_type != GDK_WINDOW_OFFSCREEN &&
-      /* or for non-shaped toplevels */
-      (private->shaped ||
-       (private->parent != NULL &&
-       private->parent->window_type != GDK_WINDOW_ROOT)) &&
-      /* or for foreign windows */
-      private->window_type != GDK_WINDOW_FOREIGN &&
-      /* or for the root window */
-      private->window_type != GDK_WINDOW_ROOT
-      )
-    {
-      GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
-    }
+      should_apply_clip_as_shape (private))
+    apply_clip_as_shape (private);
 
   if (recalculate_siblings &&
       !gdk_window_is_toplevel (private))
@@ -1470,7 +1512,7 @@ gdk_window_reparent (GdkWindow *window,
   GdkWindowObject *new_parent_private;
   GdkWindowObject *old_parent;
   GdkScreen *screen;
-  gboolean show, was_mapped;
+  gboolean show, was_mapped, applied_clip_as_shape;
   gboolean do_reparent_to_impl;
   GdkEventMask old_native_event_mask;
   GdkWindowImplIface *impl_iface;
@@ -1525,6 +1567,8 @@ gdk_window_reparent (GdkWindow *window,
       new_parent_private->window_type == GDK_WINDOW_FOREIGN)
     gdk_window_ensure_native (window);
 
+  applied_clip_as_shape = should_apply_clip_as_shape (private);
+
   old_native_event_mask = 0;
   do_reparent_to_impl = FALSE;
   if (gdk_window_has_impl (private))
@@ -1616,6 +1660,13 @@ gdk_window_reparent (GdkWindow *window,
   if (old_parent && GDK_WINDOW_TYPE (old_parent) != GDK_WINDOW_ROOT)
     recompute_visible_regions (old_parent, FALSE, TRUE);
 
+  /* We used to apply the clip as the shape, but no more.
+     Reset this to the real shape */
+  if (gdk_window_has_impl (private) &&
+      applied_clip_as_shape &&
+      !should_apply_clip_as_shape (private))
+    apply_shape (private, private->shape);
+
   if (do_reparent_to_impl)
     reparent_to_impl (private);
   else
@@ -1714,7 +1765,8 @@ gdk_window_ensure_native (GdkWindow *window)
 
   /* The shape may not have been set, as the clip region doesn't actually
      change, so do it here manually */
-  GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
+  if (should_apply_clip_as_shape (private))
+    apply_clip_as_shape (private);
 
   reparent_to_impl (private);
 
@@ -7700,6 +7752,10 @@ gdk_window_shape_combine_region (GdkWindow       *window,
 
   recompute_visible_regions (private, TRUE, FALSE);
 
+  if (gdk_window_has_impl (private) &&
+      !should_apply_clip_as_shape (private))
+    apply_shape (private, private->shape);
+
   if (old_region)
     {
       new_region = gdk_region_copy (private->clip_region);